﻿// ***********************************************************************
// Assembly         : UnitTest
// Author           : Kristian
// Created          : 05-09-2014
//
// Last Modified By : Kristian, Henrik
// Last Modified On : 05-12-2014
// ***********************************************************************

using CtrLayer;
using DBLayer;
using DBLayer.Datacontext;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using ModelLayer;
using System;
using System.Collections.Generic;
using System.Linq;

namespace UnitTest
{
    /// <summary>
    /// Class TestCtr contains tests for the Different Controller classes.
    /// </summary>
    [TestClass]
    public class TestCtr
    {
        private ICtrUser _ctrUser;
        private RLADataContext _db;
        private ICtrAchievement _ctrAchievement;
        private DbAchievementOp _dbAchievementOp;

        /// <summary>
        /// Initializes the CtrTest instance.
        /// </summary>
        [TestInitialize]
        public void Initialize()
        {
            _ctrUser = new CtrUser();
            _db = new RLADataContext();
            _ctrAchievement = new CtrAchievement();
            _dbAchievementOp = new DbAchievementOp();
        }

        /// <summary>
        /// Tests the create user functionality - should success.
        /// </summary>
        [TestMethod]
        public void TestCreateUser()
        {
            int uniquePart = _db.DBUsers.Max(user => user.userId) + 1;

            string email = "email" + uniquePart + "@def.com";
            var user1 = new User
            {
                Email = email,
                FirstName = "Henrik",
                LastName = "Mikkelsen",
                Gender = 'M',
                Password = "jegelskerkristian",
                ProfileName = "Hense" + uniquePart
            };
            user1.CurrentStatus = 0;

            //This test creates a user successfully
            int createdUser = _ctrUser.CreateUser(user1);
            Assert.IsTrue(createdUser > 0, "A user was not created as it should be");

            //This test checks that a duplicate email is not used
            createdUser = _ctrUser.CreateUser(user1);
            Assert.IsTrue(createdUser == -2, "duplicate email test failed");

            //This test checks that a null value for email is not put to the database
            user1.Email = null;
            createdUser = _ctrUser.CreateUser(user1);
            Assert.IsTrue(createdUser < 0, "null value for email test failed");

            //This test checks that a duplicate profile name is not used
            user1.Email = email + email;
            createdUser = _ctrUser.CreateUser(user1);
            Assert.IsTrue(createdUser == -3, "duplicate profile name test failed");

            //This test checks that a user with a new profile name and email is made
            user1.ProfileName += user1.ProfileName;
            user1.Email = email + email;
            createdUser = _ctrUser.CreateUser(user1);
            Assert.IsTrue(createdUser > 0, "last user creation test failed, should work");
        }

        /// <summary>
        /// Tests the get user functionality - should success.
        /// </summary>
        [TestMethod]
        public void TestGetUser()
        {
            //this test should pass a successful get
            DBUser refUser = _db.DBUsers.First();
            User user = _ctrUser.GetUser(refUser.userId);
            Assert.AreEqual(refUser.email, user.Email);

            //this test should pass a successful get

            user = _ctrUser.GetUser(refUser.email, refUser.password);
            Assert.AreEqual(refUser.email, user.Email);

            //this test should fail get user
            int userId = -1;
            user = _ctrUser.GetUser(userId);
            Assert.IsNull(user);
        }

        /// <summary>
        /// Tests the login validation.
        /// </summary>
        [TestMethod]
        public void TestLoginValidation()
        {
            string email = "Anders@Munkgaard.com";
            string password = "1234";

            CtrLogin ctr = new CtrLogin();
            Assert.IsTrue(ctr.ValidateLogin(email, password) == 1, "email/password combination could not be found in DB");
        }

        [TestMethod]
        public void TestCreateAchievement()
        {
            Achievement achievement1 = new Achievement
            {
                AchievementId = 11,
                Title = "Awesome",
                Category = "Hej",
                Criteria = "Det",
                Description = "Mugge",
                Tag = "Bisse"
            };
            achievement1.CurrentStatus = Achievement.Status.Active;

            DBUser refUser = _db.DBUsers.First();
            User user = _ctrUser.GetUser(refUser.userId);

            //This test creates a user successfully
            int createdAchievement = _ctrAchievement.CreateAchievement(user, achievement1);
            Assert.IsTrue(createdAchievement == 1, "An Achievement was not created as it should be");
        }

        [TestMethod]
        public void TestGetUserAchievement()
        {
            DBUser refDbUser = _db.DBUsers.First();
            User refUser = _ctrUser.GetUser(refDbUser.userId);
            DBUserAchievement refDbUserAchievement =
                _db.DBUserAchievements.First(ach => ach.DBUser.userId == refDbUser.userId);

            int expectedNumberOfAchievements = _db.DBUserAchievements.Count(uach => refUser.UserId == uach.fk_UserId);

            //We need a userachievement to check with. This is done by getting the first user and use the first UserAchievement attached to him in the db.
            UserAchievement refUserAchievement = new UserAchievement()
                                                 {
                                                     CurrentStatus = (UserAchievement.Status)refDbUserAchievement.status,
                                                     Achievement = _dbAchievementOp.ConvertDbAchievementToAchievement(refDbUserAchievement.DBAchievement),
                                                     User = refUser
                                                 };

            //Get all the UserAchievements attached to a user.
            List<UserAchievement> userAchList = _ctrAchievement.GetUserAchievements(refUser);

            //Check if hte list is empty.
            Assert.IsTrue(userAchList.Count > 0, "List was empty.");

            //Check if expected number of Achievements is as expected.
            Assert.AreEqual(userAchList.Count, expectedNumberOfAchievements, "The number of UserAchievements aren't as expected.");

            //As there is no equals override on the objects and the references are not identical,
            //we have to evaluate on the individual values of the objects.
            Assert.IsNotNull(userAchList.Find(x => (x.CurrentStatus == refUserAchievement.CurrentStatus &&
                                                x.Achievement.AchievementId == refUserAchievement.Achievement.AchievementId &&
                                                x.User.UserId == refUser.UserId)), "Output didn't contain expected element.");
        }

        /// <summary>
        /// Tests the get Achievement user count functionality.
        /// </summary>
        [TestMethod]
        public void TestGetAchievementUserCount()
        {
            //This gets the first Achievement in the database to use for the test
            DBAchievement dbAch = _db.DBAchievements.First();
            DbAchievementOp achOp = new DbAchievementOp();
            Achievement ach = achOp.ConvertDbAchievementToAchievement(dbAch);

            //This gets the count of users on the current Achievement
            int count = _ctrAchievement.GetAchievementUserCount(ach);

            //This test gets the positive count of the first Achievement in the database
            Assert.IsTrue(count > 0, "A wrong number of users on the current Achievement was returned");

            //This test should return nothing (zero) with a given Achievement ID that is negative
            ach.AchievementId = -1;
            count = _ctrAchievement.GetAchievementUserCount(ach);
            Assert.IsTrue(count <= 0, "Database returned found achievements even though Achievement ID was negative");
        }

        [TestMethod]
        public void TestSetUserAchievementStatus()
        {
            //Get test user
            User user = new DbUserOp().ConvertDbUserToUser(new RLADataContext().DBUsers.First());
            UserAchievement userAchievement = _ctrAchievement.GetUserAchievements(user)[0];

            UserAchievement.Status originalStatus = userAchievement.CurrentStatus;
            userAchievement.CurrentStatus = UserAchievement.Status.Rejected;

            Assert.AreNotEqual(userAchievement.CurrentStatus, originalStatus, "The two statuses were equal");

            int errorcode = _ctrAchievement.SetUserAchievementStatus(userAchievement);
            Assert.AreEqual(1, errorcode, "There was an error: {0}", errorcode);

            UserAchievement modifiedUserAchievement = _ctrAchievement.GetUserAchievements(user)[0];

            Assert.AreEqual(userAchievement.CurrentStatus, modifiedUserAchievement.CurrentStatus, "The two statuses were not equal");

            userAchievement.CurrentStatus = originalStatus;

            _ctrAchievement.SetUserAchievementStatus(userAchievement);
        }

        [TestMethod]
        public void TestSetAchievementStatus()
        {
            User user =  new DbUserOp().ConvertDbUserToUser(new RLADataContext().DBUsers.First());

            UserAchievement userAchievement = _ctrAchievement.GetUserAchievements(user)[0];
            Achievement achievement = userAchievement.Achievement;

            Achievement.Status originalStatus = achievement.CurrentStatus;
            achievement.CurrentStatus = Achievement.Status.InActive;

            Assert.AreNotEqual(achievement.CurrentStatus, originalStatus, "The two statuses were equal");

            int errorcode = _ctrAchievement.SetAchievementStatus(achievement);
            Assert.AreEqual(1, errorcode, "There was an error: {0}", errorcode);

            Achievement modifiedAchievement = userAchievement.Achievement;

            Assert.AreEqual(achievement.CurrentStatus, modifiedAchievement.CurrentStatus, "The two statuses were not equal");

            achievement.CurrentStatus = originalStatus;

            _ctrAchievement.SetAchievementStatus(achievement);
        }

        [TestMethod]
        public void TestRequestFriendship()
        {
          int[] testUserIDs = {459, 463, 464, 465, 466, 468 };  //<-- test fails because of selection of IDs and impropper setup.. DEAL WITH IT!

            User requester = _ctrUser.GetUser(testUserIDs[0]);
            try
            {
              DBFriend toDel = new DBFriend() { fk_InviterId = testUserIDs[1], fk_LowerUserId = testUserIDs[1], fk_HigherUserId = testUserIDs[2], Status = 1 };
                _db.DBFriends.Attach(toDel);
                _db.DBFriends.DeleteOnSubmit(toDel);

                toDel = new DBFriend() { fk_InviterId = testUserIDs[2], fk_LowerUserId = testUserIDs[1], fk_HigherUserId = testUserIDs[2], Status = 1 };
                _db.DBFriends.Attach(toDel);
                _db.DBFriends.DeleteOnSubmit(toDel);

                _db.SubmitChanges();
            }
            catch (Exception e)
            {
              Assert.Fail("An exception occured! \r\n" + e.Message);
            }
            
            Assert.IsTrue(_ctrUser.RequestFriendship(requester, _ctrUser.GetUser(testUserIDs[1])) < 0, "Able to insert Friendship that already exsist. ID: " + testUserIDs[1]);
            Assert.IsTrue(_ctrUser.RequestFriendship(requester, _ctrUser.GetUser(testUserIDs[2])) < 0, "Able to insert Friendship that already exsist. ID: " + testUserIDs[2]);
            Assert.IsTrue(_ctrUser.RequestFriendship(requester, _ctrUser.GetUser(testUserIDs[3])) < 0, "Able to insert Friendship that already exsist. ID: " + testUserIDs[3]);

            Assert.IsTrue(_ctrUser.RequestFriendship(_ctrUser.GetUser(testUserIDs[4]), requester) > 0, "Unable to insert Friendship. Self as Receiver.");
            Assert.IsTrue(_ctrUser.RequestFriendship(requester, _ctrUser.GetUser(testUserIDs[4])) < 0, "Able to insert Friendship that was just received.");

            Assert.IsTrue(_ctrUser.RequestFriendship(requester, _ctrUser.GetUser(testUserIDs[5])) > 0, "Unable to insert Friendship. Self as Requester.");
            Assert.IsTrue(_ctrUser.RequestFriendship(requester, _ctrUser.GetUser(testUserIDs[5])) < 0, "Able to insert Friendship that was just requested.");
        }

        [TestMethod]
        public void TestSearchUsers()
        {
            string[] keywords = { "hense", "he" };

            List<User> users = _ctrUser.SearchUserList(keywords);

            Assert.IsTrue(users.Any());
        }
    }
}